<?php

abstract class Scope implements ArrayAccess /*, Countable, IteratorAggregate*/ {
	public static $WINDOW;
	public static $APPLICATION;
	public static $DATABASE;
	public static $SESSION;
	public static $REQUEST;

	private $data = array();

	protected abstract function Hash($name);
	protected abstract function UseFileStrorage();
	private function get_filename($name){
		return Oxygen::GetTempFolder() . '/' . $this->Hash($name) . '.object';
	}
	private function save_object_to_file($name,$object){
		$filename = $this->get_filename($name);
		if (is_null($object)) {
			if (file_exists($filename))
				unlink($filename);
		}
		else {
			$f = fopen($filename,'w');
			if (flock($f,LOCK_EX)){
				fwrite($f,serialize($object));
				fclose($f);
			}
		}
	}
	private function load_object_from_file($name){
		$filename = $this->get_filename($name);
		if (!file_exists($filename))
			$r = null;
		else {
			$f = fopen($filename,'r');
			if (flock($f,LOCK_SH)){
				$size = filesize($filename);
				$r = $size==0 ? null : unserialize(fread($f, $size));
				fclose($f);
			}
		}
		$this->data[$name] = $r;
		return $r;
	}

	public function offsetExists($offset) {
		return isset($this->data[$offset]) ? true : ( $this->UseFileStrorage() ? file_exists($this->get_filename($offset)) : false );
	}
	public function offsetGet($offset) {
		return isset($this->data[$offset]) ? $this->data[$offset] : ( $this->UseFileStrorage() ? $this->load_object_from_file($offset) : null );
	}
	public function offsetSet($offset, $value) {
		if ($offset == null) throw new Exception('All variables should be named.');
		$this->data[$offset] = $value;
		if ($this->UseFileStrorage()) $this->save_object_to_file($offset,$value);
	}
	public function offsetUnset($offset) {
		if (isset($this->data[$offset])) unset($this->data[$offset]);
		if ($this->UseFileStrorage()) $this->save_object_to_file($offset,null);
	}
}

abstract class MemoryScope extends Scope {
	protected function UseFileStrorage(){ return false; }
}
abstract class FileSystemScope extends Scope {
	protected function UseFileStrorage(){ return true; }
}


class ApplicationScope extends FileSystemScope  {
	protected function Hash($name){ return 'app_'.ID::Hash($name)->AsHex(); }
}
class DatabaseScope extends FileSystemScope  {
	protected function Hash($name){ return 'dat_'.ID::Hash($name.Database::GetServer().Database::GetSchema())->AsHex(); }
}
class SessionScope extends FileSystemScope  {
	protected function Hash($name){ return 'ses_'.ID::Hash( $name.Oxygen::GetSessionID()->AsHex())->AsHex(); }
}
class WindowScope extends FileSystemScope  {
	protected function Hash($name){ return 'win_'.ID::Hash( $name.Oxygen::GetWindowID()->AsHex())->AsHex(); }
}
class RequestScope extends MemoryScope {
	protected function Hash($name){ return 'req_'.ID::Hash($name)->AsHex(); }
}

Scope::$WINDOW = new WindowScope();
Scope::$DATABASE = new DatabaseScope();
Scope::$REQUEST = new RequestScope();
Scope::$SESSION = new SessionScope();
SCOPE::$APPLICATION = new ApplicationScope();
?>
